package repository

import (
	"context"
	"gitee.com/xiao_hange/go-admin-pkg/pkg/tool"
	"go-admin/server/internal/domain"
	"go-admin/server/internal/repository/dao"
	"go.opentelemetry.io/otel"
	"strings"
)

var (
	ErrAdminDuplicate = dao.ErrAdminDuplicate
	ErrAdminNotFound  = dao.ErrAdminNotFound
)

type AdminRepository interface {
	CreateAdmin(ctx context.Context, admin domain.Admin) error
	UpdateAdmin(ctx context.Context, AdminId int64, admin domain.Admin) error
	UpdateStatus(ctx context.Context, AdminId int64, Status int32) error
	GetAdminLst(ctx context.Context, data domain.PageInfo) ([]domain.Admin, int64, error)

	FindByEmailOrLoginName(ctx context.Context, account string) (domain.Admin, error)
	GetAdminByID(ctx context.Context, adminId int64) (domain.Admin, error)
	UpdatePassword(ctx context.Context, adminId int64, password string) error
	PermissionVerification(ctx context.Context, adminId int64, paths string, isRead int32) bool
}
type adminRepository struct {
	dao     dao.AdminDao
	rbacDao dao.RbacDao
}

func NewAdminRepository(dao dao.AdminDao, rbacDao dao.RbacDao) AdminRepository {
	return &adminRepository{
		dao:     dao,
		rbacDao: rbacDao,
	}
}

func (a *adminRepository) CreateAdmin(ctx context.Context, admin domain.Admin) error {
	var daoAdmin dao.Admin
	tool.ConvertDTOToDAO(admin, &daoAdmin)
	return a.dao.Insert(ctx, daoAdmin)
}

func (a *adminRepository) UpdateAdmin(ctx context.Context, AdminId int64, admin domain.Admin) error {
	var daoAdmin dao.Admin
	tool.ConvertDTOToDAO(admin, &daoAdmin)
	return a.dao.Update(ctx, AdminId, daoAdmin)
}

func (a *adminRepository) UpdateStatus(ctx context.Context, AdminId int64, Status int32) error {
	return a.dao.UpdateStatus(ctx, AdminId, Status)
}

func (a *adminRepository) FindByEmailOrLoginName(ctx context.Context, account string) (domain.Admin, error) {
	u, err := a.dao.FindByEmailOrLoginName(ctx, account)
	if err != nil {
		return domain.Admin{}, err
	}
	var dtoAdmin domain.Admin
	tool.ConvertDAOToDTO(u, &dtoAdmin)
	return dtoAdmin, nil
}

func (a *adminRepository) GetAdminByID(ctx context.Context, adminId int64) (domain.Admin, error) {
	ctx, span := otel.Tracer("左侧菜单").Start(ctx, "Admin Repository层获取当前用户的ID")
	defer span.End()
	u, err := a.dao.GetAdminByID(ctx, adminId)
	if err != nil {
		return domain.Admin{}, err
	}
	var dtoAdmin domain.Admin
	tool.ConvertDAOToDTO(u, &dtoAdmin)
	return dtoAdmin, nil
}

func (a *adminRepository) GetAdminLst(ctx context.Context, data domain.PageInfo) ([]domain.Admin, int64, error) {
	lists, total, err := a.dao.GetAdminData(ctx, data)
	if err != nil {
		return nil, 0, err
	}
	result := make([]domain.Admin, len(lists))
	for i, list := range lists {
		var dtoAdmin domain.Admin
		tool.ConvertDAOToDTO(list, &dtoAdmin)
		result[i] = dtoAdmin
	}
	return result, total, err
}

func (a *adminRepository) UpdatePassword(ctx context.Context, adminId int64, password string) error {
	return a.dao.UpdatePassword(ctx, adminId, password)
}

func (a *adminRepository) PermissionVerification(ctx context.Context, adminId int64, path string, isRead int32) bool {
	admin, err := a.dao.GetAdminByID(ctx, adminId)
	if err != nil {
		return false
	}
	//TODO 超级管理员 开放全部权限
	roleIds := tool.ParseIntSlice(admin.RoleIds, ",")
	if a.rbacDao.IsSuperAdministrator(ctx, roleIds) {
		return true
	}
	paths := a.generateWildcard(path)
	return a.rbacDao.DoYouHavePermission(ctx, roleIds, paths, isRead)
}

func (a *adminRepository) generateWildcard(name string) []string {
	if !strings.HasPrefix(name, "/") {
		return []string{name}
	}

	wildcards := []string{name}
	segments := strings.Split(strings.Trim(name, "/"), "/")

	currentPath := ""
	for _, segment := range segments {
		currentPath += "/" + segment
		wildcards = append(wildcards, strings.TrimRight(currentPath, "/")+"/"+"*")
	}

	return wildcards
}
